#include "serial/SerialComm.h"
#include <iostream>
#include <stdlib.h>
#ifdef __linux__
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#endif

using namespace std;

SerialComm::SerialComm(string porta) {
	this->porta = porta;
	hPorta = 0;
}

int SerialComm::iniciar() {
	int result = EXIT_FAILURE;
#if _WIN32 || _WIN64
	hPorta = CreateFile(porta.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
	OPEN_EXISTING, 0, NULL);

	if (hPorta == INVALID_HANDLE_VALUE) {
		result = GetLastError();
		cerr << "Erro abrindo a porta de comunicacao!" << endl;
	} else {
		// configura timeouts
		COMMTIMEOUTS cto = { 1, 100, 1000, 0, 0 };
		if (!SetCommTimeouts(hPorta, &cto)) {
			cout << "Nao foi possivel configurar timeouts de comunicacao!"
					<< endl;
		}

		// configura acesso aa porta
		DCB dcb;
		memset(&dcb, 0, sizeof(dcb));
		dcb.DCBlength = sizeof(dcb);
		dcb.BaudRate = CBR_9600;
		dcb.Parity = NOPARITY;
		dcb.StopBits = ONESTOPBIT;
		dcb.ByteSize = 8;

		if (!SetCommState(hPorta, &dcb)) {
			result = GetLastError();
			cerr << "Erro configurando a porta de comunicacao!" << endl;
		} else {
			result = EXIT_SUCCESS; // sem erros
		}
	}
#endif
#ifdef __linux__
	hPorta = open(porta.c_str(),
			O_RDWR | O_NOCTTY |
			O_NDELAY);
	if (hPorta == -1)
	{
		cerr << "Erro abrindo a porta de comunicacao!" << endl;
	}
	else
	{
		fcntl(hPorta, F_SETFL, 0);

		result = EXIT_SUCCESS; // sem erros
	}
#endif
	// espera ateh que porta serial esteja pronta para receber comandos
	if (result == EXIT_SUCCESS)
	{
		Sleep(2000);
	}

	return result;
}

string SerialComm::ler(long unsigned int bytesLer,
		long unsigned int &bytesLidos) {
	string id = "";
	bytesLidos = 0;
	long unsigned int tentativas = 5, bytes = 0;
	char buffer[32] = { 0 };
	do {
#if defined _WIN32 || _WIN64
		ReadFile(hPorta, buffer, bytesLer, &bytes, NULL);
#endif
#ifdef __linux__
		bytes = read(hPorta, buffer, bytesLer);
#endif
		if (bytes > 0) {
			id = id + string(buffer);
			bytesLidos += bytes;
		}
		tentativas--;
	} while ((bytesLidos < bytesLer) && (tentativas > 0));
	return id;
}

void SerialComm::escrever(int comando,
		long unsigned int &bytesEscritos) {
	bytesEscritos = 0;
	char bcomando = (char)comando;
#if defined _WIN32 || _WIN64
	WriteFile(hPorta, &bcomando, sizeof(bcomando), &bytesEscritos, NULL);
#else
	bytesEscritos = write(hPorta, &bcomando, sizeof(bcomando));
#endif
}

void SerialComm::escrever(int comando,
		int parametro,
		long unsigned int &bytesEscritos) {
	bytesEscritos = 0;
	char comandoPar[2];
	comandoPar[0] = (char)comando;
	comandoPar[1] = (char)parametro;

#if _WIN32 || _WIN64
	WriteFile(hPorta, &comandoPar, sizeof(comandoPar), &bytesEscritos, NULL);
#else
	bytesEscritos = write(hPorta, &comandoPar, sizeof(comandoPar));
#endif
}

void SerialComm::escrever(int comando,
		int parametro1,
		int parametro2,
		long unsigned int &bytesEscritos) {
	bytesEscritos = 0;
	char comandoPars[3];
	comandoPars[0] = (char)comando;
	comandoPars[1] = (char)parametro1;
	comandoPars[2] = (char)parametro2;

#if defined _WIN32 || _WIN64
	WriteFile(hPorta, &comandoPars, sizeof(comandoPars), &bytesEscritos, NULL);
#else
	bytesEscritos = write(hPorta, &comandoPars, sizeof(comandoPars));
#endif
}

void SerialComm::finalizar() {
#if _WIN32 || _WIN64
	CloseHandle(hPorta);
#endif
}
